package cate.game.rank.po;

import cate.common.table.d.GDRank;
import cate.common.util.XT;
import cate.game.db.mongo.rank.RankMongo;
import cate.game.role.Role;
import cate.game.role.RoleSnapshot;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

public class RankSPO<E extends Rank> extends RankMongo {
    /** 排行榜列表 */
    protected List<E> list;

    public void initialize(){
        if(list == null){
            list = new ArrayList<>();
        }
        Iterator<E> iter = list.iterator();
        int idx = 0;
        while (iter.hasNext()) {
            E e = iter.next();
            if (e == null || e.owner == null || StringUtils.isBlank(e.owner.uid) || idx > getRankNum()) {
                iter.remove();
                continue;
            }
            idx++;
        }
    }

    /** 获取排行榜列表 */
    public List<E> getList() {
        return list;
    }

    /** 获取排行榜列表（浅拷贝） */
    public List<E> listCopy() {
        return new ArrayList<>(list);
    }

    /** 根据主角唯一ID查找上榜记录 */
    public E findByRoleUid(String roleUid) {
        for (E item : list) {
            if (StringUtils.equals(roleUid, item.owner.uid)) {
                return item;
            }
        }
        return null;
    }

    /**
     * 根据唯一ID获取对应的排名
     *
     * @return -1表示没有进入排名
     */
    public int getIndex(Role role) {
        if (role == null) {
            return -1;
        }
        return getIndex(role.getUid());
    }

    /**
     * 根据唯一ID获取对应的排名
     *
     * @return -1表示没有进入排名
     */
    public int getIndex(String uid) {
        for (int i = 0; i < list.size(); i++) {
            E item = list.get(i);
            if (StringUtils.equals(item.owner.uid, uid)) {
                return i + 1;
            }
        }
        return -1;
    }

    public void clear(){
        list.clear();
    }

    public void updateRole(Role role) {
        //只从缓存读，读不到拉倒
        E e = findByRoleUid(role.getUid());
        if(e != null){
            e.updateOwner(role);
        }
    }

    /**
     * 默认从大到小排
     */
    public void record(Role role, long newValue) {
        record(role, newValue, true);
    }

    /**
     * 默认从大到小排
     */
    public void record(Role role, long newValue, boolean sort) {
        if (list.size() >= getRankNum()) {
            E last = list.get(list.size() - 1);
            if (last.value > newValue) {
                // 没有进排行榜
                return;
            }
        }
        // 是否已经上榜
        E item = findByRoleUid(role.getUid());
        long preValue = item == null ? 0 : item.value;
        if (item != null) {
            // 已经在榜上了
            item.updateOwner(role, newValue);
        } else {
            // 之前没有上榜
            E e = createRank(role, newValue);
            if (list.size() >= getRankNum()) {
                // 如果排行榜已经满了，那就把最后一名给去掉
                list.remove(list.size() - 1);
            }
            list.add(e);
        }
        if(sort && preValue != newValue){
            sort();
        }
    }

    /**
     * 默认从大到小排
     */
    public void record(RoleSnapshot roleSnapshot, long newValue, boolean sort) {
        if (list.size() >= getRankNum()) {
            E last = list.get(list.size() - 1);
            if (last.value > newValue) {
                // 没有进排行榜
                return;
            }
        }
        // 是否已经上榜
        E item = findByRoleUid(roleSnapshot.uid);
        long preValue = item == null ? 0 : item.value;
        if (item != null) {
            // 已经在榜上了
            item.updateOwner(roleSnapshot, newValue);
        } else {
            // 之前没有上榜
            E e = createRank(roleSnapshot, newValue);
            if (list.size() >= getRankNum()) {
                // 如果排行榜已经满了，那就把最后一名给去掉
                list.remove(list.size() - 1);
            }
            list.add(e);
        }
        if(sort && preValue != newValue){
            sort();
        }
    }

    /**
     * 排行榜记录数
     * @return num
     */
    protected int getRankNum(){
        return GDRank.RANK_LIMIT;
    }

    /** 执行排序 */
    public void sort(){
        list.sort(Comparator.comparing(E::getValue)
                .reversed()
                .thenComparing(E::getRecordTime));
    }

    public List<E> getElementByRange(int from, int to){
        return getElementByRange(from ,to, null);
    }

    public List<E> getElementByRange(int from, int to, Set<Integer> exclude){
        List<E> elements = new ArrayList<>();
        if(to < 0 || from > to){
            return elements;
        }
        //修正
        from = Math.max(0, from);
        to = Math.min(to, list.size() - 1);
        for(int i=from; i<=to; ++i){
            if(exclude != null && exclude.contains(i)){
                continue;
            }
            elements.add(list.get(i));
        }
        return elements;
    }

    /**
     * 找比角色低xx位和高xx位的人
     * @param role role
     * @param lower 低xx位
     * @param higher 高xx位
     * @return list
     */
    public List<E> getElementByRoleRange(Role role, int lower, int higher){
        int idx = getIndex(role);
        if(idx < 0){
            idx = list.size() - 1;
        }
        return getElementByRange(idx-lower, idx+higher);
    }

    /**
     * 根据玩家的排名来找比他高xx位，到低xx位的人，排除主角自己
     * @param role role
     * @param lower 低xx位
     * @param higher 高xx位
     * @return list
     */
    public List<E> getElementByRoleRangeExcludeSelf(Role role, int lower, int higher){
        int idx = getIndex(role);
        if(idx < 0){
            idx = list.size() - 1;
        }
        Set<Integer> exclude = new HashSet<>();
        exclude.add(idx);
        return getElementByRange(idx-lower, idx+higher, exclude);
    }

    /**
     * 根据玩家的排名来找比他高xx位，到低xx位的人，排除主角自己和列表中的排名
     * @param role role
     * @param lower 低xx位
     * @param higher 高xx位
     * @return list
     */
    public List<E> getElementByRoleRangeExcludes(Role role, int lower, int higher, Set<Integer> excludes){
        int idx = getIndex(role);
        if(idx < 0){
            idx = list.size() - 1;
        }
        if(excludes == null){
            excludes = new HashSet<>();
        }
        excludes.add(idx);
        return getElementByRange(idx-lower, idx+higher, excludes);
    }

    public List<E> randomNumRoleRangeExcludeSelf(Role role, int lower, int higher, int num, int atLeastLowerNum, int atLeastHigherNum){
        List<E> resList = new ArrayList<>();
        if(list.size() <= num){
            return getElementByRoleRangeExcludeSelf(role, lower, higher);
        }
        int idx = getIndex(role);
        if(idx < 0){
            idx = list.size() - 1;
        }
        //0没有更靠前的， 1只有0是更前的，2只有0和1， 以此类推
        atLeastLowerNum = Math.min(idx, atLeastLowerNum);
        atLeastHigherNum = Math.min(list.size() - idx, atLeastHigherNum);
        int from = Math.max(0, idx-lower);
        int to = Math.min(idx+higher, list.size() - 1);

        Set<Integer> randomSet = new HashSet<>();
        if(atLeastLowerNum > 0){
            while(atLeastLowerNum > 0 || randomSet.size() >= num){
                int random = XT.randomRange(from, idx - 1);
                if(randomSet.contains(random)){
                    continue;
                }
                randomSet.add(random);
                atLeastLowerNum -- ;
            }
        }
        if(atLeastHigherNum > 0){
            while(atLeastHigherNum > 0 || randomSet.size() >= num){
                int random = XT.randomRange(idx + 1, to);
                if(randomSet.contains(random)){
                    continue;
                }
                randomSet.add(random);
                atLeastHigherNum -- ;
            }
        }
        if(randomSet.size() < num){
            for(int i=0; i<num-randomSet.size(); ++i){
                int random = XT.randomRange(from, to);
                while(randomSet.contains(random) || random == idx){
                    random = XT.randomRange(from, to);
                }
            }
        }
        return resList;
    }


    /**
     * 默认从大到小排
     */
    public long recordAddAndRtn(Role role, long addValue) {
        long rtnValue = 0;
        // 是否已经上榜
        E item = findByRoleUid(role.getUid());
        if (item != null) {
            // 已经在榜上了
            item.updateOwner(role, item.getValue() + addValue);
            sort();
        }
        return rtnValue;
    }

    protected E createRank(Role role, long value){
        return (E) new Rank(role, value);
    }

    protected E createRank(RoleSnapshot roleSnapshot, long value){
        return (E) new Rank(roleSnapshot, value);
    }
}
